'use strict';
/**
 * iceView v1.0.1
 * MIT License By www.iceui.cn
 * 作者：ICE
 * ＱＱ：308018629
 * 官网：www.iceui.cn
 * 说明：版权完全归iceui所有，转载和使用请注明版权
 * -------------------------------------------------------------
 * 模板引擎
 * iceView 2020-06-28
 */
var ice = ice || {};
ice.view = function(options) {
	var reg = /\{\{([^\}][\s\S]+?)\}\}/g;
	//克隆对象
	function cloneObj(obj){
	    if (typeof obj !== 'object') return obj;
	    let newObj = {};
	    for (let key in obj) newObj[key] = cloneObj(obj[key]);
	    return newObj;
	}
	//阻止冒泡
	function sp(event) {
		window.event ? window.event.cancelBubble = true : event.stopPropagation();
	}
	//阻止默认行为
	function pd(event) {
		window.event ? window.event.returnValue = false : event.preventDefault();
	}
	//消息队列
	function msg() {
        this.list = {};
    }
    msg.prototype = {
        addList: function (node,key) {
        	this.list[key] = this.list[key] ? this.list[key] : [];
            this.list[key].push(node);
        },
        update: function (key) {
        	if(this.list[key] && this.list[key].length){
        		this.list[key].forEach(function (node) {
	                node.update();
	            });
        	}
        }
    };
	function iceView(options) {
        this.data = options;
        this.msg = new msg();
        this.global = false;
        this.el = document.getElementsByClassName('iceView');
        if(!this.el.length) return;
        //保存数据所有key
        this.dataKey = [];
        Object.keys(options).forEach((k)=>{
        	if(k[0]=='$'){
        		return;
        	}
        	this.dataKey.push(k);
        });
        //备份数据，不会被监听
        this.datas = cloneObj(options);
        //劫持数据
        this.kidnap(options);
        //遍历所有节点
        for(var i=0;i<this.el.length;i++){
        	var el = this.el[i];
        	//创建div
			if(el.tagName == 'TEMPLATE'){
				var div = document.createElement('div');
				div.innerHTML = el.innerHTML;
				el.parentNode.insertBefore(div,el);
				el = div;
			}
        	this.eachNode(el);
        }
        //初始化完成，执行回调
        this.data.onload && this.data.onload.bind(this.data)(this.data);
        return this.data;
    }
    iceView.prototype = {
    	//劫持对象属性setter、getter
	    kidnap: function (data) {
	        if (!data || typeof data !== 'object') {
	            return;
	        }
	        Object.keys(data).forEach((key)=>{
	            this.reactive(data, key, data[key])
	        });
	    },
	    // 响应式数据绑定
	    reactive: function (data, key, val) {
	        //递归
	        this.kidnap(data[key]);
	        var that = this;
	        Object.defineProperty(data, key, {
	            get: function () {
	                // 添加thread到对象msg
	                if (msg.target) {
	                    that.msg.addList(msg.target,key);
	                }
	                return val;
	            },
	            set: function (newVal) {
	                if (newVal === val) {
	                    return;
	                } else {
	                    val = newVal;
	                    that.datas = cloneObj(that.data);
	                    that.kidnap(newVal); //劫持新数据
	                    that.msg.update(key); //发出通知
	                }
	            }
	        });
	    },

	    //递归编译所有子节点
	    eachNode: function (el,data) {
	    	if(data)el.global = data;
	    	this.compile(el);
	        var e = el.childNodes;
	        if (e.length) {
	            for (var i = 0; i < e.length; i++) {
	            	if(data)e[i].global = data;
	                this.compile(e[i]);
	                this.eachNode(e[i],data);
	            }
	        }
	    },
    	
    	//编译
	    compile: function (node) {
	    	if(node.init) return;
	    	var that = this;
	        // 节点类型为元素
	        if (node.nodeType === 1) {
	            var attr = node.attributes;
	            // 解析属性
	            for (var i = 0; i < attr.length; i++) {
	                var key = attr[i].nodeName; //属性名
	                var value = attr[i].nodeValue.trim(); //属性值
	                if (key.indexOf('i-on') !== -1) {
	                	var arr = key.split('.'),type=false;
	                	if(arr.length>1){
	                		type = arr[1],key = arr[0];
	                	}
	                	var eventType = key.slice(4);
	                	var fn = function(e,f){
	                		type == 'stop' && sp(e);
	                		type == 'prevent' && pd(e);
	                		if(arr[2]){
	                			type = arr[1]+arr[2];
	                			if(type == 'stopprevent' || type == 'preventstop'){
		                			sp(e),pd(e);
		                		}
	                		}
	                		f()
	                	};
	                	if (reg.test(value)) {
                			var code = RegExp.$1;
	                		(function(code){
	                			node.addEventListener(eventType, function (e){
	                				fn(e,function(){
	                					that.reviseEnv(code,node.global);
	                				})
	                			}, false)
	                		})(that.global?that.global+code:code);
				        }else{
		                    var cb = this.data[value];
		                    if (value && eventType && cb) {
		                    	node.addEventListener(eventType, function(e){
		                			fn(e,function(){
		                				cb.bind(that.data)(node,e);
		                			})
		                		}, false);
		                    }
				        }
				        node.removeAttribute(key);
	                }
	                if(key == 'i-model') {
	                	if(node.type == 'text' || node.type == 'password'){
	                		node.addEventListener('input', function (e) {
		                        that.data[value] = e.target.value;
		                    })
	                	}else if(node.type == 'checkbox' || node.type == 'radio'){
	                		node.addEventListener('click', function (e) {
		                        that.data[value] = this.checked;
		                    })
	                	}else if(node.tagName == 'SELECT'){
	                		node.addEventListener('change', function (e) {
		                        that.data[value] = this.value;
		                    })
	                	}else if(node.tagName == 'TEXTAREA'){
	                		node.addEventListener('input', function (e) {
		                        that.data[value] = this.value;
		                    })
	                	}
	                    node.removeAttribute(key);
	                    new thread(this, node, key, value);
	                }
	                if(key == 'i-html') {
	                	node.removeAttribute(key);
	                	new thread(this, node, key, value);
	                }
	                
	                if(key == 'i-show') {
	                	node.removeAttribute(key);
	                	new thread(this, node, key, value);
	                }
	                if(key == 'i-for') {
	                	node.removeAttribute(key);
	                	node.hideNode = document.createComment('');
	                	node.parentNode.replaceChild(node.hideNode,node);
	                	node.itemNodeList = [];
	                	new thread(this, node, key, value);
	                }
	                if(key == 'i-if') {
	                	node.hideNode = document.createTextNode('');
	                	node.removeAttribute(key);
	                	new thread(this, node, key, value);
	                }
	                if (reg.test(value)) {
		                new thread(this, node, key, value, 'attr');
			        }
	            }
	        }
	        // 节点类型为text
	        if (node.nodeType === 3) {
	            if (reg.test(node.nodeValue)) {
	                new thread(this, node, false, node.nodeValue);
	            }
	        }
	        node.init = true;
	    },
	    getData:function(name){
	    	if(name && name.length){
	    		var a = name.indexOf('"');
	    		var b = name.indexOf("'");
	    		if(a>b){
	    			name = name.replace(/'[^']+'/g,' ').replace(/"[^"]+"/g,' ');
	    		}else{
	    			name = name.replace(/"[^"]+"/g,' ').replace(/'[^']+'/g,' ');
	    		}
	    		name = name.match(/\w+/g);
	    		if(name){
	    			name.forEach((k)=>{
	    				if(this.dataKey.includes(k)){
				    		this.data[k];
				    	}
	    			})
	    		}
	    	}
	    },
	    //环境变量
	    reviseEnv:function($str,$data,$debug){
	    	var $v = '';
	    	try {
	    		(function($this){
	    			$this.dataKey.forEach((k)=>{
			    		if(typeof $this.datas[k] == 'function'){
			    			$v += 'var '+k+'=$this.datas.'+k+'.bind($this.data);';
			    		}else{
			    			$v += 'var '+k+'=$this.datas.'+k+';';
			    		}
			    	});
			    	if($data){
			    		for(var key in $data){
			    			$v += 'var '+key+'=$data.'+key+';';
			    		}
			    	}
			    	if($this.global)$v += $this.global;
			    	$v += $str ? $str : '';
			    	if($debug) console.log($v);
		    		$v = eval($v);
	    		}).call(this.data,this);
			}
			catch(err) {
				$v = '';
			    console.log(err);
			}
			return $v;
	    },
    };
    //初始化线程
    function thread(vm, node, key, value, type) {
        msg.target = this;
        this.vm = vm;
        this.node = node;
        this.key = key;
        this.value = value;
        this.content = value;
        this.type = type;
        this.vm.getData(value);
        this.update();
        msg.target = null;
    }
    thread.prototype = {
        update: function () {
            this.get();
            var that = this;
            if(this.type == 'attr'){
            	var value = this.content.replace(reg, function(a, b){
                    b = b.trim();
                    if (b.length) {
                    	return that.vm.reviseEnv(b,that.node.global);
                    }
                    return a;
                });
                this.node.setAttribute(this.key,value);
                return;
            }
            if (this.key == 'i-if') {
            	var value = this.vm.reviseEnv(this.value,this.node.global);
            	//转为bool值判断是否显示
                if(Boolean(value)){
                	let pn = this.node.hideNode.parentNode;
                	if(pn)pn.replaceChild(this.node,this.node.hideNode);
                }else{
                	let pn = this.node.parentNode;
                	if(pn)pn.replaceChild(this.node.hideNode,this.node);
                }
                return;
            }
            if (this.key == 'i-for'){
            	var list = this.vm.data[this.value];
            	if (reg.test(this.value)) {
	                var code = RegExp.$1;
	                list = this.vm.reviseEnv(code,this.node.global);
	            }
	            if(!list || !list.length) list = []; //防止报错
            	for(var i=0;i<this.node.itemNodeList.length;i++){
            		let pn = this.node.itemNodeList[i].parentNode;
            		if(pn)pn.removeChild(this.node.itemNodeList[i]);
            	}
            	this.node.itemNodeList = [];
            	if(typeof list == 'object'){
            		for(var k in list){
            			var itemNode = this.node.cloneNode(true);
            			this.node.itemNodeList.push(itemNode);
            			this.node.hideNode.parentNode.insertBefore(itemNode,this.node.hideNode);
            			this.vm.eachNode(itemNode,{
            				item:list[k],
            				index:k
            			});
            		}
            		this.vm.global = false;
            	}
                return;
            }
            if (this.key == 'i-show') {
            	var value = this.value;
            	if (reg.test(this.value)) {
	                value = this.vm.reviseEnv(RegExp.$1,this.node.global);
	            }
            	this.node.style.display = Boolean(value) ? 'initial' : 'none';
                return;
            }
            if (this.node.nodeType == 1) {
                if (this.node.tagName == 'INPUT') {
                	if(this.node.type == 'checkbox' || this.node.type == 'radio'){
                		this.node.checked = Boolean(this.text);
                	}else{
                		this.node.value = this.text;
                	}
                }
                if (this.node.tagName == 'TEXTAREA') {
                	this.node.value = this.text;
                }
                if (this.node.tagName == 'SELECT') {
                	this.node.value = this.text;
                }
                if (this.key == 'i-html') {
                    this.node.innerHTML = this.text;
                }
            }else if(this.node.nodeType == 3){
            	this.node.nodeValue = this.text;
            }
        },
        // 获取data中的属性值
        get: function () {
            // 触发相应属性的get
            if (this.node.nodeType == 1) {
                this.text = this.vm.data[this.value];
            } else if (this.node.nodeType == 3) {
                this.text = this.content.replace(reg, (a, b) => {
                    b = b.trim();
                    if (b.length) {
                    	return this.vm.reviseEnv(b,this.node.global);
                    }
                    return a;
                });
            }
        }
    }
    return new iceView(options);
};